#include <iostream>
#include <assert.h>
#include <unistd.h>
#include <fcntl.h>
#include "commutils.h"

#include <map>

using namespace std;

int tcp_server(int port)
{
    struct sockaddr_in local;
    memset(&local, 0,  sizeof(sockaddr_in));
    //local.sin_len = sizeof(sockaddr_in);
    local.sin_addr.s_addr = htonl(INADDR_ANY);
    local.sin_port = htons(port);
    local.sin_family = AF_INET;
    
    
    int fd = socket(AF_INET, SOCK_STREAM, 0 );
    if (fd < 0 ){
        cout << "tcp_server socket call failed! errno is " << errno << endl;
        return -1;
    }
    
    
    int on = 1;
    if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))){
        ::close(fd);
        cout << "tcp_server setsockopt call failed! errno is " << errno << endl;
        return -1;
    }
    
    const char chOpt=1;
    setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &chOpt, sizeof(char));
    
    int iret = ::bind(fd, (struct sockaddr*)&local, sizeof(local));
    if(iret != 0){
        cout << "tcp_server bind call failed! errno is " << errno << endl;
        ::close(fd);
        return -1;
    }

    if(listen(fd, 500)){
        cout << "tcp_server listen call failed! errno is " << errno << endl;
        ::close(fd);
        return -1;
    }
    
    cout << "tcp_server listen on port =  " << port << endl;
    return fd;
}


int tcp_client( const char* hostIp,  int port)
{
    struct sockaddr_in peer;
    memset(&peer, 0,  sizeof(sockaddr_in));
    //peer.sin_len = sizeof(sockaddr_in);
    inet_aton(hostIp, &peer.sin_addr);
    peer.sin_port = htons(port);
    peer.sin_family = AF_INET;
    
    int fd = socket(AF_INET, SOCK_STREAM, 0 );
    if (fd < 0){
        cout << "tcp_client socket call failed! errno is " << errno << endl;
        return -1;
    }
    
    const char chOpt=1;
    setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &chOpt, sizeof(char));

    if ( connect(fd, (struct sockaddr * )&peer, sizeof(peer))){
        cout << "tcp_client connect call failed! errno is " << errno << endl;
        ::close(fd);
        return -1;
    }
    
    return fd;
}

int tcp_write(int fd, const char* buffer, int len)
{
    int misslen = len;
    while (misslen > 0) {
        int rlen = (int)write(fd, buffer + (len - misslen), misslen);
        misslen -= rlen;
    }
    
    return len;
}

int tcp_read(int fd, const char* buffer, int len)
{
    int misslen = len;
    while (misslen > 0) {
        int rlen = (int)read(fd, (void *)(buffer + (len - misslen)), misslen);
        misslen -= rlen;
    }
    
    return len;
}


void   itoa   (   unsigned   long   val,   char   *buf,   unsigned   radix   )
{
    char   *p;                                 /*   pointer   to   traverse   string   */
    char   *firstdig;                   /*   pointer   to   first   digit   */
    char   temp;                             /*   temp   char   */
    unsigned   digval;                 /*   value   of   digit   */
    
    p   =   buf;
    firstdig   =   p;                       /*   save   pointer   to   first   digit   */
    
    do   {
        digval   =   (unsigned)   (val   %   radix);
        val   /=   radix;               /*   get   next   digit   */
        
        /*   convert   to   ascii   and   store   */
        if   (digval   >   9)
            *p++   =   (char   )   (digval   -   10   +   'a');     /*   a   letter   */
        else
            *p++   =   (char   )   (digval   +   '0');               /*   a   digit   */
    }   while   (val   >   0);
    
    /*   We   now   have   the   digit   of   the   number   in   the   buffer,   but   in   reverse
     order.     Thus   we   reverse   them   now.   */
    
    *p--   =   '\0';                         /*   terminate   string;   p   points   to   last   digit   */
    
    do   {
        temp   =   *p;
        *p   =   *firstdig;
        *firstdig   =   temp;       /*   swap   *p   and   *firstdig   */
        --p;
        ++firstdig;                   /*   advance   to   next   two   digits   */
    }   while   (firstdig   <   p);   /*   repeat   until   halfway   */
}

int fd_write_buf(int fd, const char *buf, int len){
    if (fd == -1) return -1;
    
    int count = 0;
    ssize_t sendLen = 0;
    
    while (count < len && (sendLen = write(fd, buf, len - count)) > 0) {
        count += sendLen;
    }
    
    return count;
}

int fd_read_buf(int fd, char *buf, int maxLen) {
    if (fd == -1) return -1;
    
    int count = 0;
    ssize_t readLen = 0;
    
    while ((readLen = read(fd, buf, maxLen - count)) > 0) {
        count += readLen;
    }
    
    return count;
}

int fd_send_msg(int fd, const char *msg, int len) {
    
    fd_write_buf(fd, (char *)&len, sizeof(int));
    
    return fd_write_buf(fd, msg, len);
}

int fd_recv_msg(int fd, char *msg, int maxLen) {
    
    int len = 0;
    fd_read_buf(fd, (char *)&len, sizeof(int));
    
    return fd_read_buf(fd, (char *)msg, min(len, maxLen));
}


